﻿using System;
using RayDen.Library.Core;
using RayDen.Library.Core.Primitives;

namespace RayDen.Library.Components.Surface.Microfacet
{
    public class BlinnDistribution : MicrofacetDistribution
    {
        float exponent;

        public BlinnDistribution(float e)
        {
            exponent = e;
            if (exponent > 1000f || float.IsNaN(exponent))
                exponent = 1000f;
        }
        public override float D(ref Vector wh)
        {
            float costhetah = Math.Abs(BrdfBase.CosTheta(ref wh));
            return (exponent + 2f) *
                   MathLab.INVTWOPI *
                   (float)Math.Pow(Math.Max(0f, costhetah), exponent);
        }

        public override void Sample_f(ref Vector wo, out Vector wi, float u1, float u2, out float pdf)
        {
            float costheta = (float)Math.Pow(u1, 1f / (exponent + 1));
            float sintheta = MathLab.Sqrt(Math.Max(0f, 1f - costheta * costheta));
            float phi = u2 * 2f * MathLab.M_PI;
            Vector H = Vector.SphericalDirection(sintheta, costheta, phi);
            if ((wo & H) < 0f) H = -H;
            wi = -wo + 2f * (wo & H) * H;
            float blinn_pdf = ((exponent + 2f) *
                               (float)Math.Pow(costheta, exponent)) /
                              (2f * MathLab.M_PI * 4f * (wo & H));
            pdf = blinn_pdf;
        }

        public override float Pdf(ref Vector wo, ref Vector wi)
        {
            Vector H = (wo + wi).Normalize();
            float costheta = Math.Abs(H.z);
            float blinn_pdf = ((exponent + 2f) * (float)Math.Pow(costheta, exponent)) / (2f * MathLab.M_PI * 4f * (wo & H));
            return blinn_pdf;
        }
    }
}